home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
presto
/
presto10.lha
/
src
/
dynix_timer.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
5KB
|
234 lines
/*
* Fast timers for Dynix.
*
*
* Last modified: 6/16/89
* by: sandstro
* reason: added the equivalent of segvh()
* to the mmap'd kernel code
*
* Last modified: 1/2/88
* by: bnb
* reason: add print function
*
* Last modified: 12/21/87
* by: bnb
* reason: add these comments
*
*/
#include <sys/param.h>
#include <sys/file.h>
#include <signal.h>
#include <stddef.h>
#include <sys/mman.h>
#include <osfcn.h>
#include <nlist.h>
#include <stream.h>
#include "presto.h"
#include <time.h>
extern void fatalerror();
static void check_for_hole();
static shared_t struct nlist Namelist[] = {
{ "_time" },
#define X_TIME 0
{ "" }
};
#define VMUNIX "/dynix"
#define KMEM "/dev/kmem"
shared_t Spinlock timer_lock;
shared_t Spinlock *t_lock = &timer_lock;
private_t int t_kmemfd = -1;
shared_t struct timeval *t_tv = 0;
shared_t int t_tv_all_valid = 0; // valid in all address spaces
private_t int t_tv_im_valid = 0; // valid in this address space
shared_t int t_refcnt = 0;
shared_t unsigned long timer_offt;
shared_t int timer_pgsz;
shared_t caddr_t timer_base;
//
// Always succeed, even if we can't map
//
void
Timer::init()
{
t_lock->lock();
t_refcnt++;
if (t_tv) {
// At least one address space has already
// initialized this timer.
t_starttime = getabsolutetime();
t_lock->unlock();
return;
}
//
// ELSE, must map kernel time var into our address space
//
if (nlist(VMUNIX, Namelist) < 0) {
perror("Cant get namelist");
goto out;
}
if (Namelist[X_TIME].n_type == 0) {
cerr << "Help... namelist is insane\n";
goto out;
}
t_kmemfd = open(KMEM, O_RDONLY, 0);
if (t_kmemfd < 0) {
perror("open");
cerr << "Can't open kmem for time class\n";
goto out;
}
if (lseek(t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0) {
perror("lseek");
cerr << "Can't lseek kmem for time class\n";
goto out;
}
timer_pgsz = getpagesize();
timer_offt = Namelist[X_TIME].n_value & ~(timer_pgsz-1);
timer_base = grab_nonmalloc_hunk (timer_pgsz);
if (timer_base == (char *) -1) {
perror ("shbrk");
error ("Shbrk failed in Timer init");
goto out;
}
if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,t_kmemfd, timer_offt) < 0) {
perror("mmap");
error("Can't map kmem first time");
goto out;
}
t_tv = (struct timeval*)(timer_base + Namelist[X_TIME].n_value - timer_offt);
t_tv_im_valid = 1;
t_starttime = getabsolutetime();
t_lock->unlock();
return;
out:
if (t_tv == 0) {
t_tv = new timeval; // static tv for ::gettimeofday
t_tv_all_valid = 1;
}
close(t_kmemfd);
t_kmemfd = -1; // must use system call
t_lock->unlock();
return;
}
Timer::~Timer()
{
t_lock->lock();
#ifdef SANITY
if (t_refcnt <= 0) {
cerr << "Warning:non-positive refcnt on time destructor\n";
}
#endif
t_refcnt--;
if (t_refcnt == 0) {
if (t_kmemfd < 0) {
t_tv_all_valid = 0;
delete t_tv;
} else {
close(t_kmemfd);
t_tv = 0;
t_kmemfd = -1;
}
t_lock->unlock();
delete t_lock;
} else
t_lock->unlock();
}
double
Timer::getabsolutetime()
{
check_for_hole();
return (double)t_tv->tv_sec +
((double)(t_tv->tv_usec) * 1.0e-6);
}
char*
Timer::getasciitime()
{
check_for_hole();
return ctime((long*)&t_tv->tv_sec);
}
/*
struct timeval*
Timer::gettimeofday()
{
check_for_hole();
if (t_kmemfd < 0) { // couldn't map
::gettimeofday(t_tv,0);
}
return t_tv;
}
*/
void
Timer::print(ostream& s)
{
check_for_hole();
s << form("(Timer)this= 0x%x,", this) <<
"t_lock= " << t_lock << "\n";
s << "t_tv= " << t_tv->tv_sec << ":" << t_tv->tv_usec << "\n";
s << "t_refcnt=" << t_refcnt << ", t_starttime = " << t_starttime;
}
// The following routine, check_for_hole(), allows several address spaces
// to check at the last minute whether they have memory mapped /dev/kmem,
// and to map it if necessary. Sequent offers something similar for
// shbrk(), called segvh(). Segvh() is discussed in section 5.2 of
// ``A Parallel Programming Process Model'' by Beck and Olien,
// a paper distributed at the 1988 SURF in Newport Beach, CA.
// Segvh() doesn't work here, because segvh() assumes that you
// want to map the file descriptor _shm_fd to your address space.
static void check_for_hole()
{
// This routine assumes that Timer::init() has been called.
if (t_tv_all_valid == 0) {
// At least one routine succeeded in mmapping the kernel,
// and no processes have yet tried and failed.
if (t_tv_im_valid == 0) {
// It wasn't us that succeeded in mmapping the kernel.
t_kmemfd = open (KMEM, O_RDONLY, 0);
if (t_kmemfd < 0) {
perror ("open");
error ("open kmem for Timer");
}
if (lseek (t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0) {
perror ("lseek");
error ("lseek kmem for Timer");
}
if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,
t_kmemfd, timer_offt) < 0) {
perror ("mmap");
error ("mmap kmem for Timer");
}
}
}
}